/*
 * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id: NodeIteratorBase.java,v 1.2.4.1 2005/09/06 09:37:02 pvedula Exp $
 */

package com.sun.org.apache.xalan.internal.xsltc.dom;

import com.sun.org.apache.xalan.internal.xsltc.NodeIterator;
import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;

/**
 * @author Jacek Ambroziak
 * @author Santiago Pericas-Geertsen
 * @author Morten Jorgensen
 */
public abstract class NodeIteratorBase implements NodeIterator {

  /**
   * Cached computed value of last().
   */
  protected int _last = -1;

  /**
   * Value of position() in this iterator. Incremented in
   * returnNode().
   */
  protected int _position = 0;

  /**
   * Store node in call to setMark().
   */
  protected int _markedNode;

  /**
   * Store node in call to setStartNode().
   */
  protected int _startNode = NodeIterator.END;

  /**
   * Flag indicating if "self" should be returned.
   */
  protected boolean _includeSelf = false;

  /**
   * Flag indicating if iterator can be restarted.
   */
  protected boolean _isRestartable = true;

  /**
   * Setter for _isRestartable flag.
   */
  public void setRestartable(boolean isRestartable) {
    _isRestartable = isRestartable;
  }

  /**
   * Initialize iterator using a node. If iterator is not
   * restartable, then do nothing. If node is equal to END then
   * subsequent calls to next() must return END.
   */
  abstract public NodeIterator setStartNode(int node);

  /**
   * Reset this iterator using state from last call to
   * setStartNode().
   */
  public NodeIterator reset() {
    final boolean temp = _isRestartable;
    _isRestartable = true;
    // Must adjust _startNode if self is included
    setStartNode(_includeSelf ? _startNode + 1 : _startNode);
    _isRestartable = temp;
    return this;
  }

  /**
   * Setter for _includeSelf flag.
   */
  public NodeIterator includeSelf() {
    _includeSelf = true;
    return this;
  }

  /**
   * Default implementation of getLast(). Stores current position
   * and current node, resets the iterator, counts all nodes and
   * restores iterator to original state.
   */
  public int getLast() {
    if (_last == -1) {
      final int temp = _position;
      setMark();
      reset();
      do {
        _last++;
      } while (next() != END);
      gotoMark();
      _position = temp;
    }
    return _last;
  }

  /**
   * Returns the position() in this iterator.
   */
  public int getPosition() {
    return _position == 0 ? 1 : _position;
  }

  /**
   * Indicates if position in this iterator is computed in reverse
   * document order. Note that nodes are always returned in document
   * order.
   */
  public boolean isReverse() {
    return false;
  }

  /**
   * Clones and resets this iterator. Note that the cloned iterator is
   * not restartable. This is because cloning is needed for variable
   * references, and the context node of the original variable
   * declaration must be preserved.
   */
  public NodeIterator cloneIterator() {
    try {
      final NodeIteratorBase clone = (NodeIteratorBase) super.clone();
      clone._isRestartable = false;
      return clone.reset();
    } catch (CloneNotSupportedException e) {
      BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
          e.toString());
      return null;
    }
  }

  /**
   * Utility method that increments position and returns its
   * argument.
   */
  protected final int returnNode(final int node) {
    _position++;
    return node;
  }

  /**
   * Reset the position in this iterator.
   */
  protected final NodeIterator resetPosition() {
    _position = 0;
    return this;
  }
}
